package com.godyao.mall.gateway.config;

import cn.hutool.core.util.ArrayUtil;
import com.godyao.mall.gateway.exception.RequestAccessDeniedHandler;
import com.godyao.mall.gateway.exception.RequestAuthenticationEntryPoint;
import com.godyao.mall.gateway.model.WhiteUrls;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.ReactiveAuthenticationManager;
import org.springframework.security.authorization.ReactiveAuthorizationManager;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.SecurityWebFiltersOrder;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.oauth2.server.resource.web.server.ServerBearerTokenAuthenticationConverter;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.security.web.server.authentication.AuthenticationWebFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsWebFilter;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;

/**
 * 由于spring cloud gateway使用的Flux，因此需要使用@EnableWebFluxSecurity注解开启，而不是平常的web应用了
 * @author godyao
 * @date 2022/4/2
 */
@Configuration
@EnableWebFluxSecurity
public class SecurityConfig {

    /**
     * 解决跨域问题
     * @return
     */
    @Bean
    public CorsWebFilter corsWebFilter() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        //1.配置跨域
        //允许哪种请求头跨域
        corsConfiguration.addAllowedHeader("*");
        //允许哪种方法类型跨域 get post delete put
        corsConfiguration.addAllowedMethod("*");
        // 允许哪些请求源跨域
        //corsConfiguration.addAllowedOrigin("*");
        corsConfiguration.addAllowedOrigin("http://localhost:8001");
        // 是否携带cookie跨域
        corsConfiguration.setAllowCredentials(true);

        // 允许跨域的路径
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", corsConfiguration);
        return new CorsWebFilter(source);
    }

    /**
     * 白名单放行
     */
    @Autowired
    private WhiteUrls whiteUrls;

    /**
     * token校验管理器
     */
    @Autowired
    private ReactiveAuthenticationManager tokenAuthenticationManager;

    /**
     * JWT的鉴权管理器
     */
    @Autowired
    private ReactiveAuthorizationManager authorizationManager;

    /**
     * token过期的异常处理
     */
    @Autowired
    private RequestAuthenticationEntryPoint authenticationEntryPoint;

    /**
     * 权限不足的异常处理
     */
    @Autowired
    private RequestAccessDeniedHandler requestAccessDeniedHandler;

    @Bean
    SecurityWebFilterChain webFluxSecurityFilterChain(ServerHttpSecurity http) {
        // 认证过滤器
        AuthenticationWebFilter authenticationWebFilter = new AuthenticationWebFilter(tokenAuthenticationManager);
        authenticationWebFilter.setServerAuthenticationConverter(new ServerBearerTokenAuthenticationConverter());

        http
                .httpBasic().disable()
                .csrf().disable()
                .authorizeExchange()
                // 白名单直接放行
                .pathMatchers(ArrayUtil.toArray(whiteUrls.getUrls(), String.class)).permitAll()
                // 其他请求必须鉴权
                .anyExchange().access(authorizationManager)
                .and().exceptionHandling()
                // 认证失败异常处理器
                .authenticationEntryPoint(authenticationEntryPoint)
                // 权限不足异常处理器
                .accessDeniedHandler(requestAccessDeniedHandler)
                .and()
                // 添加跨域过滤器
                .addFilterAt(corsWebFilter(), SecurityWebFiltersOrder.CORS)
                .addFilterAt(authenticationWebFilter, SecurityWebFiltersOrder.AUTHENTICATION);
        return http.build();

    }


}
